
package sparrowGui
{
	import flash.display.Sprite;
	import flash.events.Event;
	
	import sparrowGui.impl.IBaseComponent;
	import sparrowGui.utils.PubFun;
	import sparrowGui.vars.BaseComponentVars;

	/**
	 * Component.as
	 * @author Pelephone
	 * 基本组件,有画背景边框,框架背景图,背景颜色,背景渐变等属性
	 * 有点类似于一个div
	 */
	public class Component extends Sprite implements IBaseComponent
	{
//		public var forceDraw:Boolean = false;
		private var _tag:int = -1;
		private var _enabled:Boolean = true;
		protected var _skin:Sprite;
		private var _style:Object;
		
		private var listenerMap:Object = {};
		
		public static const COMPONENT_DRAW:String = "component_draw";

		/**
		 * 构造
		 */
		public function Component(vars:Object=null)
		{
			vars = vars || (new BaseComponentVars())
			style = vars;
			listenerMap = {};
			
			init();
		}

		/**
		 * Initilizes the component.
		 */
		protected function init():void
		{
		}
		
		
		///////////////////////////////////
		// public methods
		///////////////////////////////////
		
		override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			super.addEventListener(type,listener,useCapture,priority,useWeakReference);
			var ls:Array = listenerMap[type] as Array;
			if(!ls) listenerMap[type] = [];
			listenerMap[type].push(listener);
		}
		
		override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			super.removeEventListener(type,listener,useCapture);
			var ls:Array = listenerMap[type] as Array;
			if(!ls) return;
			var lid:int = ls.indexOf(listener);
			if(lid>=0) ls.splice(lid,1);
			if(!ls.length) delete listenerMap[type];
		}
		
		
		public function removeTypeListeners(type:String):void
		{
			listenerMap[type] = null;
			delete listenerMap[type];
		}
		
		public function removeAllListeners():void
		{
			listenerMap = {};
		}
		
/*		//此函数是removeEventListener的辅助，removeEventListener只能移除对应消息的某个监听者
		//removeNoteListener可以移除所有监听者．type,listener同时不为空则用法和removeEventListener一样
		//用法：如果type是空的话，移除所有监听者和消息．如果listener为空则移除监听type消息的所有监听者
		public function removeNoteListener(type:String=null,listener:Function=null):void
		{
			if(type!=null){
				if(listener!=null){
					super.removeEventListener(type,listener);
					return;
				}
				for(var i:int=0;i<listenerMap.length;i++){
					var t:String = listenerMap[i++] as String;
					var f:Function = listenerMap[i] as Function;
					if(t==type){
						super.removeEventListener(t,f);
						listenerMap.splice(i,2);
						i-=2;
					}
				}
			}else{
				while(listenerMap.length){
					t = listenerMap.shift();
					f = listenerMap.shift();
					super.removeEventListener(t,f);
				}
			}
		}*/
		
		/**
		 * 移动元件到新位置
		 * @param xpos the x position to move the component
		 * @param ypos the y position to move the component
		 */
		public function setXY(xpos:Number, ypos:Number):void
		{
			x = Math.round(xpos);
			y = Math.round(ypos);
		}
		
		/**
		 * 设置宽高
		 * Sets the size of the component.
		 * @param w The width of the component.
		 * @param h The height of the component.
		 */
		public function setSize(w:Number, h:Number):void
		{
			width = w;
			height = h;
		}
		
/*		//设计新样式，重绘此组件
		protected function setStyle(vars:Object):void
		{
			style = vars;
			nextDraw();
		}*/
		
		/**
		 * 基本绘制函数
		 */
		protected function draw():void
		{
			dispatchEvent(new Event(Component.COMPONENT_DRAW));
		}
		
		/**
		 * Marks the component to be redrawn on the next frame.
		 * 此方法相当于设了一个缓存，如set width和set height不是设一个重绘一次，而是两个参数都设好了再重绘
		 */
		protected function nextDraw():void
		{
/*			// 如果强制绘制为真则不需要等下帧,直接重绘
			if(forceDraw){
				draw();
				return;
			}*/
			if(style.hasOwnProperty("isDelayDraw") && style.isDelayDraw){
				draw();
				return;
			}
			removeEventListener(Event.ENTER_FRAME, onInvalidate);
			addEventListener(Event.ENTER_FRAME, onInvalidate);
		}
		
		///////////////////////////////////
		// event handlers
		///////////////////////////////////
		
		
		/**
		 * Called one frame after invalidate is called.
		 */
		public function onInvalidate(event:Event=null):void
		{
			removeEventListener(Event.ENTER_FRAME, onInvalidate);
			draw();
		}
		
		///////////////////////////////////
		// getter/setters
		///////////////////////////////////
		
		/**
		 * Sets/gets the width of the component.
		 */
		override public function set width(w:Number):void
		{
			style.width = w;
			nextDraw();
			dispatchEvent(new Event(Event.RESIZE));
		}
		/**
		 * Sets/gets the height of the component.
		 */
		override public function set height(h:Number):void
		{
			style.height = h;
			nextDraw();
			dispatchEvent(new Event(Event.RESIZE));
		}
		
		override public function get width():Number
		{
			if(style.isBgFill) return style.width;
			else return super.width;
		}
		
		override public function get height():Number
		{
			if(style.isBgFill) return style.height;
			else return super.height;
		}
		
/*		override public function get width():Number
		{
//			if(hasEventListener(Event.ENTER_FRAME)) return style.width;
			if(skin && skin.width>style.width) return skin.width;
			else
				return style.width;
		}
		override public function get height():Number
		{
//			if(hasEventListener(Event.ENTER_FRAME)) return style.height;
			if(skin && skin.height>style.height) return skin.height;
			else
				return style.height;
		}*/
		
		/**
		 * Sets/gets in integer that can identify the component.
		 */
		public function set tag(value:int):void
		{
			_tag = value;
		}
		public function get tag():int
		{
			return _tag;
		}
		
		// 是否整型经x,y坐标
		public function set isIntXY(val:Boolean):void
		{
			style.isIntXY = val;
			nextDraw();
		}
		
		// 是否整型经x,y坐标
		public function set isBgFill(val:Boolean):void
		{
			style.isBgFill = val;
			nextDraw();
		}
		
		/**
		 * Overrides the setter for x to always place the component on a whole pixel.
		 */
		override public function set x(value:Number):void
		{
			super.x = style.isIntXY?Math.round(value):value;
		}
		
		/**
		 * Overrides the setter for y to always place the component on a whole pixel.
		 */
		override public function set y(value:Number):void
		{
			super.y = style.isIntXY?Math.round(value):value;
		}

		/**
		 * Sets/gets whether this component is enabled or not.
		 */
		public function set enabled(value:Boolean):void
		{
			_enabled = value;
			mouseEnabled = mouseChildren = _enabled;
            tabEnabled = value;
			alpha = _enabled ? 1.0 : 0.5;
		}
		
		public function get enabled():Boolean
		{
			return _enabled;
		}

		public function dispose():void
		{
			removeAllListeners();
//			listenerMap = null;
			PubFun.SafeRemoveChild(skin);
			_skin = null;
//			PubFun.SafeRemoveChild(this);
			PubFun.killObject(style);
			PubFun.killObject(this);
		}

		public function get style():Object
		{
			return _style;
		}

		public function set style(value:Object):void
		{
			_style = value;
			nextDraw();
		}

		public function get skin():Sprite
		{
			return _skin;
		}
	}
}